package lk.icta.common.service.impl;

import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.lang.GeoLocation;
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.exif.GpsDirectory;

import lk.icta.common.AppConstants;
import lk.icta.common.dao.DocumentManagementDao;
import lk.icta.common.dto.GeoPoint;
import lk.icta.common.entity.Document;
import lk.icta.common.entity.DocumentCategory;
import lk.icta.common.service.DocumentManagementService;
import lk.icta.common.util.AlfrescoUtil;
import lk.icta.common.util.KmlWriter;
import lk.icta.core.entity.ModuleType;
import lk.icta.user.entity.User;
import org.alfresco.webservice.util.ContentUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * @author Mahesha Kalpanie
 */
public class DocumentManagementServiceImpl implements DocumentManagementService {

    private static final Logger logger = LoggerFactory.getLogger(DocumentManagementServiceImpl.class);
    private final DocumentManagementDao documentManagementDao;

    public DocumentManagementServiceImpl(DocumentManagementDao documentManagementDao) {
        this.documentManagementDao = documentManagementDao;
    }

    private void copyDocument(User user, Document document, String oldLocation, long oldFileName) {
        logger.debug("Copy Document {} - ", user.getUsername());
        //TODO: check permissions
        try {
            documentManagementDao.addDocument(user, document);
            String oldFileFullName, fileName;
            if (document.getExtension() != null) {
                oldFileFullName = oldFileName + document.getExtension();
                fileName = document.getId() + document.getExtension();
            } else {
                oldFileFullName = oldFileName + "";
                fileName = document.getId() + "";
            }

            logger.debug("new Location {} - ", document.getLocation());
            logger.debug("new file Name {} - ", fileName);
            File fileToCreate = new File(document.getLocation(), fileName);
            logger.debug("old Location {} - ", oldLocation);
            logger.debug("old file Name {} - ", oldFileFullName);
            File file = new File(oldLocation, oldFileFullName);
            FileUtils.copyFile(file, fileToCreate);
        } catch (IOException e) {
            //TODO: handle exeption
            e.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void uploadfiles(User user, List<Document> docList, long id) {
        if (docList != null) {
            logger.debug("Upload Files {} - ", user.getUsername());
            for (Document document : docList) {
                addDocument(user, document, id);
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    private void updateDocument(User user, Document document) {
        logger.debug("Update Document {} - ", user.getUsername());
        documentManagementDao.updateDocument(user, document);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public String findFilePath(User user, long documentId) {
        Document document = getDocumentById(user, documentId);
        logger.debug("document found with id : {}", document.getId());
        try {
            if (document.getExtension() != null) {
                return document.getLocation() + document.getId() + document.getExtension().toLowerCase();
            } else {
                return document.getLocation() + document.getId();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<Document> getDocumentsByModuleAndModuleId(User user, ModuleType module, long moduleId) {
        logger.debug("Get Documents By Module And Module Id {} - ", user.getUsername());
        return documentManagementDao.getDocumentsByModuleAndModuleId(user, module, moduleId);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public Document getDocumentById(User user, long id) {
        logger.debug("Get Document By Id {} - ", user.getUsername());
        return documentManagementDao.getDocumentById(user, id);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteDocumentById(User user, long id) {
        logger.debug("Delete Document By Id {} - ", user.getUsername());
        documentManagementDao.deleteDocumentById(user, id);
    }

    private void addDocument(User user, Document document, long id) {
        logger.debug("Add Document {} - ", user.getUsername());
        //TODO: check permissions
        String path = AppConstants.CONTENT_ROOT + document.getModuleType().getId() + "/" + id + "/";
        File file = document.getFile();
        String fileName = document.getFileName();

        if (file != null) {
            int dotPos = fileName.indexOf('.');
            if (dotPos != -1) {
                document.setExtension(fileName.substring(dotPos));
            }
            document.setLocation(path);
            document.setModuleId(id);

            documentManagementDao.addDocument(user, document);

            if (document.getExtension() != null) {
                fileName = document.getId() + document.getExtension().toLowerCase();
            } else {
                fileName = document.getId() + "";
            }

            File fileToCreate = new File(document.getLocation(), fileName);
            try {

                if (".kml".equals(document.getExtension())) {
                    logger.debug("Add Document KML file" + document.getExtension());

                    KmlWriter kmlWriter = new KmlWriter();
                    File createdKml = kmlWriter.writeKmlFile(file);
                    FileUtils.copyFile(createdKml, fileToCreate);
                } else {
                    FileUtils.copyFile(file, fileToCreate);

                    /*
                    //add content to DMS
                    String uploadURL = AlfrescoUtil.getUrlForAlfrescoServer(id);
                     //todo: add file as bite array
                    document.setUploadUrl(uploadURL);
                    document.setFileContent(ContentUtils.convertToByteArray(new FileInputStream(file)));
                    AlfrescoUtil.addContent(document);
                    //update uploadURL and documentUuid
                    documentManagementDao.updateDocument(user, document);
                    */
                }

            } catch (IOException e) {
                //TODO: handle exeption
                e.printStackTrace();
                logger.error(e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public void uploadExistingfiles(User user, long id, long newId,
                                    ModuleType moduleType, ModuleType newModuleType) {

        logger.debug("Upload Existing files {} - ", user.getUsername());

        List<Document> docList = documentManagementDao.getDocumentsByModuleAndModuleId(user, moduleType, id);

        String path = AppConstants.CONTENT_ROOT + moduleType.getId() + "/" + id + "/";
        String newPath = AppConstants.CONTENT_ROOT + newModuleType.getId() + "/" + newId + "/";

        if (docList != null) {
            for (Document doc : docList) {
                Document document = new Document();
                document.setDocumentName(doc.getDocumentName());
                document.setContentType(doc.getContentType());
                document.setLocation(newPath);
                document.setModuleId(newId);
                document.setModuleType(newModuleType);
                if (doc.getExtension() != null) {
                    document.setExtension(doc.getExtension());
                }
                if (doc.getDocumentCategory() != null) {
                    document.setDocumentCategory(doc.getDocumentCategory());
                }

                copyDocument(user, document, path, doc.getId());
            }
        }
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<DocumentCategory> getDocumentCategoryList(User user) {
        return documentManagementDao.getDocumentCategoryList(user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<DocumentCategory> getDocumentCategoryListByModuleId(User user, ModuleType moduleType) {
        return documentManagementDao.getDocumentCategoryListByModuleId(user, moduleType);
    }


    @Transactional(propagation = Propagation.SUPPORTS)
    public void deleteDocumentAtLandAssociationDefineAM(List<Long> deleteDocList, User user) {
       logger.debug("Delete documents list : {}", deleteDocList.size());
        for (long dId : deleteDocList) {
            logger.debug("Delete doc id: {} \n", dId);
            Document document = getDocumentById(user, dId);
            if (document != null) {
                if (deleteServerDoc(document)) {
                    deleteDocumentById(user, dId);
                }
            }
        }
    }

    private boolean deleteServerDoc(Document doc) {
        try {
            String extension = doc.getExtension();
            if (extension == null) {
                extension = "";
            }
            logger.debug("File Path :{}", doc.getLocation() + doc.getModuleId() + extension);
            File file = new File(doc.getLocation() + doc.getId() + extension);
            if (file.delete()) {
                logger.debug("File is deleted");
                return true;
            } else {
                logger.debug("File Delete operation is failed.");
                return false;
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.debug("File Delete operation Exception {}:", e.getMessage());
            return false;
        }
    }
}
